﻿//TODO: test, MultiscaleRetinex

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Drawing;
using System.Drawing.Imaging;

namespace LowLevelGraphics.Filter
{
    /// <summary>
    /// Illumination correction
    /// </summary>
    public class MultiscaleRetinex : BaseImageFilter
    {
        protected double[] m_aSigma; //different scales of gaussian sigma 
        protected double[] m_aWidths; //weighting term of gaussian sigma
        protected int m_nSize;        //size of filter

        /// <summary>
        /// Constructor
        /// </summary>
        public MultiscaleRetinex()
            : this(new double[]{0}, new double[]{1,2}, 10)
        {
        }

        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="sigmas"></param>
        /// <param name="widths"></param>
        /// <param name="size"></param>
        public MultiscaleRetinex(double[] sigmas, double[] widths, int size)
        {
            this.m_aSigma = sigmas;
            this.m_nSize = size;
            this.m_aWidths = widths;
        }

        /// <summary>
        /// internal for cloning instance
        /// </summary>
        /// <param name="_multiScaleRetinex"></param>
        internal MultiscaleRetinex(MultiscaleRetinex _multiScaleRetinex)
        {
            this.m_aSigma = _multiScaleRetinex.Sigma;
            this.m_aWidths = _multiScaleRetinex.Widths;
            this.m_nSize = _multiScaleRetinex.m_nSize;
        }

        /// <summary>
        /// Get/Sets the size
        /// </summary>
        public int Size
        {
            get { return m_nSize; }
            set { m_nSize = value; }
        }

        /// <summary>
        /// Gets or sets Sigma
        /// </summary>
        public double[] Sigma
        {
            get { return m_aSigma; }
            set { m_aSigma = value; }
        }

        /// <summary>
        /// Gets or sets width
        /// </summary>
        public double[] Widths
        {
            get { return m_aWidths; }
            set { m_aWidths = value; }
        }

        /// <summary>
        /// Execute
        /// </summary>
        /// <param name="_bitmap"></param>
        /// <returns></returns>
        public override UnsafeBitmap Execute(UnsafeBitmap _bitmap)
        {
            int count = m_aSigma.Length;
            Bitmap bmp;
            double[,] sum = new double[_bitmap.Width, _bitmap.Height];

            int i = 0;
            BitmapFunctions bitmapFunctions = null;
            for (i = 0; i < count; i++)
            {
                new GaussianBlur((int)m_aSigma[i]).Execute(_bitmap);

                bitmapFunctions = new BitmapFunctions(_bitmap);
                sum = bitmapFunctions.SumBitmap(sum, m_aWidths[i]);
                bitmapFunctions.Dispose();
            }
            new PixelDivision(true, 0.0f, (float)sum[0,0], 1.0f, false).Execute(_bitmap);
            new Normalize().Execute(_bitmap);
            return _bitmap;
        }

        /// <summary>
        /// Clone this instance
        /// </summary>
        /// <returns></returns>
        public override object Clone()
        {
            return new MultiscaleRetinex(this);
        }
    }
}
